﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using $ext_safeprojectname$.redismodel;
using $ext_safeprojectname$.usermodels;
using Volo.Abp.DependencyInjection;
using Volo.Abp.ObjectMapping;

namespace $ext_safeprojectname$
{
    /// <summary>
    /// 
    /// </summary>
    public class ModelHelper : ISingletonDependency
    {
        private IAppCache _cache;
        private IServiceProvider _serviceProvider;
        private readonly IObjectMapper ObjectMapper;



        //scop
        //protected readonly HttpContext _httpContext;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="serviceProvider"></param>
        /// <param name="cache"></param>
        /// <param name="map"></param>
        public ModelHelper(IServiceProvider serviceProvider, IAppCache cache, IObjectMapper map)
        {
            this._serviceProvider = serviceProvider;
            _cache = cache;
            ObjectMapper = map;
        }



        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<PartInfoDto> ItemPartInfo(int id)
        {
            var item = await _cache.GetAsync<PartInfoDto>($"{PublicString._cacheheadpart}{id}");
            if (item == null || item == default)
            {
                using var _scope = _serviceProvider.CreateScope();
                using var _dbContext = _scope.ServiceProvider.GetRequiredService<$ext_safeprojectname$DbContext>();
                var find = _dbContext.PartInfo.Where(x => x.Id == id).AsNoTracking().FirstOrDefault();
                if (find != null && find != default)
                {
                    item = ObjectMapper.Map<PartInfo, PartInfoDto>(find);
                    await _cache.SetAsync<PartInfoDto>($"{PublicString._cacheheadpart}{id}", item, 3600);
                }
            }
            return item;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<bool> RemovePartItemCacheAsync(int id)
        {
            return await _cache.DeleteAsync($"{PublicString._cacheheadpart}{id}");
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<UserInfoDto> ItemUserInfo(int id)
        {
            var item = await _cache.GetAsync<UserInfoDto>($"{PublicString._cacheheaduser}{id}");
            if (item == null || item == default)
            {
                using var _scope = _serviceProvider.CreateScope();
                using var _dbContext = _scope.ServiceProvider.GetRequiredService<$ext_safeprojectname$DbContext>();
                var find = _dbContext.UserInfo.Where(x => x.Id == id).AsNoTracking().FirstOrDefault();
                if (find != null && find != default)
                {
                    item = ObjectMapper.Map<UserInfo, UserInfoDto>(find);
                    await _cache.SetAsync<UserInfoDto>($"{PublicString._cacheheaduser}{id}", item, 3600);
                }
            }
            return item;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<bool> RemoveUserItemCacheAsync(int id)
        {
            return await _cache.DeleteAsync($"{PublicString._cacheheaduser}{id}");
        }


        /// <summary>
        /// 获取自己级下级账号列表 缓存30~70秒
        /// </summary>
        /// <param name="_dbContext"></param>
        /// <param name="userid"></param>
        /// <returns></returns>
        /// <exception cref="$ext_safeprojectname$Exception"></exception>
        public async Task<List<UserInfoListDto>> ReadMyAndNextUserList(I$ext_safeprojectname$DbContext _dbContext, int userid)
        {

            //可以做缓存处理
            var find = await _cache.GetAsync<List<UserInfoListDto>>(string.Format(PublicString.CacheMyNextUserList, userid));
            if (find != null && find.Count > 0)
            {
                return find;
            }
            //获取我的部门
            var mypart = await (from a in _dbContext.BindUserPart.Where(x => x.UserId == userid)
                                join b in _dbContext.PartInfo on a.PartId equals b.Id into c
                                from d in c.DefaultIfEmpty()
                                select new PartInfoListDto()
                                {
                                    Id = d.Id,
                                    Name = d.Name,
                                    FatherStr = d.FatherStr
                                }).AsNoTracking().ToListAsync();

            if (mypart != null && mypart.Any())
            {
                IQueryable<int> query = null;
                foreach (var item in mypart)
                {
                    var one = _dbContext.PartInfo.Where(x => x.Id != item.Id && x.FatherStr.StartsWith(item.FatherStr)).Select(x => x.Id);
                    if (query == null)
                    {
                        query = one;
                    }
                    else
                    {
                        query = query.Union(one);
                    }
                }
                if (query != null)
                {
                    var userdtolist = await (from a in _dbContext.BindUserPart.Where(x => query.Contains(x.PartId))
                                             join b in _dbContext.UserInfo on a.UserId equals b.Id into d
                                             from f in d.DefaultIfEmpty()
                                             select new UserInfoListDto()
                                             {
                                                 Id = f.Id,
                                                 UserName = f.UserName,
                                                 UserHead = f.UserHead
                                             }).Distinct().ToListAsync();

                    //把自己加上去
                    if (!userdtolist.Select(x => x.Id).Contains(userid))
                    {
                        var myuser = _dbContext.UserInfo.Where(x => x.Id == userid).AsNoTracking().FirstOrDefault();
                        if (myuser != null && myuser != default)
                        {
                            userdtolist.Insert(0, ObjectMapper.Map<UserInfo, UserInfoListDto>(myuser));
                        }
                    }

                    _cache.Set<List<UserInfoListDto>>(string.Format(PublicString.CacheMyNextUserList, userid), userdtolist, new Random().Next(30, 70));

                    return userdtolist;
                }
                else
                {
                    throw new $ext_safeprojectname$Exception("没有获取到下级部门的绑定信息，无法获取");
                }
            }
            else
            {
                throw new $ext_safeprojectname$Exception("当前账号没有绑定部门信息，无法获取");
            }

        }


        /// <summary>
        /// 判定一个账号是否有另外一个账号的所属权，一般用于上下级的判定
        /// </summary>
        /// <param name="_dbContext"></param>
        /// <param name="userid"></param>
        /// <param name="targetuserid"></param>
        /// <returns></returns>
        public async Task<bool> HasUserRole(I$ext_safeprojectname$DbContext _dbContext, int userid, int targetuserid)
        {
            var userdtolist = await ReadMyAndNextUserList(_dbContext, userid);
            if (userdtolist.Any())
            {
                if (userdtolist.Select(x => x.Id).Contains(targetuserid))
                {
                    return true;
                }
            }

            return false;
        }


        /// <summary>
        /// 是否有权限
        /// </summary>
        /// <param name="_model"></param>
        /// <param name="_role"></param>
        /// <param name="_token"></param>
        /// <returns></returns>
        public (int code, bool role) HasRole(string _model, string _role, string _token = null)
        {
            if (!string.IsNullOrEmpty(_token))
            {
                var roles = _cache.Get<List<RoleInfoListDto>>(_token);
                if (roles != null && roles.Any())
                {
                    var root = roles.Where(x => (x.Model == "root" && x.Name == "root") || (x.Model == _model && x.Name == _role)).Any();
                    return (403, root);
                }
                else
                {
                    return (401, false);
                }
            }
            return (401, false);
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="_dbContext"></param>
        /// <param name="userid"></param>
        /// <param name="_model"></param>
        /// <param name="_role"></param>
        /// <returns></returns>
        public async Task<bool> HasRole(I$ext_safeprojectname$DbContext _dbContext,int userid,string _model, string _role)
        {

            var user = await ItemUserInfo(userid);
            var roles = _dbContext.RoleInfo.Where(x => _dbContext.GradeRole.Where(x => x.GradeId == user.GradeId).Select(x => x.RoleId).Contains(x.Id)).AsNoTracking().ToList();
            if (roles != null && roles.Count > 0)
            {
                return roles.Where(x => (x.Model == "root" && x.Name == "root") || (x.Model == _model && x.Name == _role)).Any();
            }
            return false;
        }



    }
}
